#pragma once
#include "log.hpp"
#include "Task.hpp"
#include "Threadpool.hpp"
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <cstring>
#include <unordered_map>
#include "Daemon.hpp"

const int defaultfd = -1;
const std::string defaultip = "0.0.0.0";
const int backlog = 10;

enum
{
    SOCKET_ERR = 1,
    BIND_ERR,
    LISTEN_ERR,
    USAGEERR0R,
};

class Tcpserver;

class Task;

class Threaddate
{
private:
public:
    Threaddate(int fd, std::string &ip, uint16_t &port, Tcpserver *t)
        : _sockfd(fd), _clientip(ip), _clientport(port), _tsvr(t)
    {
    }
    ~Threaddate()
    {
    }

private:
    int _sockfd;
    std::string _clientip;
    uint16_t _clientport;
    Tcpserver *_tsvr;
};

class Tcpserver
{
private:
    log lg;

public:
    Tcpserver(const uint16_t &port, const std::string &ip = defaultip)
        : _listensock(defaultfd), _port(port), _ip(ip)
    {
    }

    void Init()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock == -1)
        {
            lg(Fatel, "socket create error", "errno %d", "errno string is %s", errno, strerror(errno));
            exit(SOCKET_ERR);
        }
        lg(Info, "socket create success listensock is %d", _listensock);

        int opt = 1;
        setsockopt(_listensock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));

        sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        inet_aton(_ip.c_str(), &(local.sin_addr));

        if (bind(_listensock, (sockaddr *)&local, sizeof(local)) < 0)
        {
            lg(Fatel, "socket bind error", "errno %d", "errno string is %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info, "socket bind success listensock is %d", _listensock);

        if (listen(_listensock, backlog) < 0)
        {
            lg(Fatel, "socket listen error", "errno %d", "errno string is %s", errno, strerror(errno));
            exit(LISTEN_ERR);
        }
        lg(Info, "socket listen success listensock is %d", _listensock);
    }

    void run()
    {
        Daemon();
        threadpool<Task>::GetInstance()->Init();
        while (1)
        {
            sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd=accept(_listensock, (sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                lg(Warning, "socket accept error", "errno %d", "errno string is %s", errno, strerror(errno));
                continue;
            }
            uint16_t clientport=ntohs(client.sin_port);
            char clientip[32];
            socklen_t iplen=sizeof(clientip);
            inet_ntop(AF_INET,&client,clientip,iplen);
            lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, clientip, clientport);
            Task t(sockfd,clientport,clientip);
            threadpool<Task>::GetInstance()->push(t);
        }
    }
    ~Tcpserver()
    {}

private:
    int _listensock;
    uint16_t _port;
    std::string _ip;
};